package com.wan37.client.handler;

import com.google.protobuf.Message;
import com.googlecode.protobuf.format.JsonFormat;
import com.wan37.client.Client;
import com.wan37.client.global.reference.SpringContextHolder;
import com.wan37.client.message.received.ReceiveMsg;
import com.wan37.client.service.PVEFightingService;
import com.wan37.client.service.cache.RoleServiceCache;
import com.wan37.client.service.cache.TradingShopCache;
import com.wan37.client.service.cache.UserServiceCache;
import com.wan37.common.uuid.UUIDUtil;
import com.wan37.protobuf.analysis.ParseMap;
import com.wan37.protobuf.constant.AllRoleLabel;
import com.wan37.protobuf.constant.CommonEmail;
import com.wan37.protobuf.message.client2server.auth.Auth;
import com.wan37.protobuf.message.client2server.game.*;
import com.wan37.protobuf.util.ClientProtoUtils;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

import static com.wan37.client.Client.clientHandler;

/**
 * 客户数逻辑处理类
 *
 * @author ly
 */
@ChannelHandler.Sharable
public class ClientHandler extends SimpleChannelInboundHandler<Message> {

    private static final Logger logger = LoggerFactory.getLogger(ClientHandler.class);

    public final static ClientHandler instance = new ClientHandler();

    public static ClientHandler getInstance() {
        return instance;
    }

    private RoleServiceCache roleServiceCache;
    private UserServiceCache userServiceCache;
    private PVEFightingService pveFightingService;

    /**
     * 客户端连接到服务器的ctx
     */
    private static ChannelHandlerContext gateServerConnCtx;

    /**
     * 该客户端登录之后的userId
     */
    public String selfId = "";

    /**
     * 登录是否成功的标记
     */
    public volatile boolean login_success = false;

    public volatile boolean isRole = false;

    /**
     * 当前所在场景
     */
    public volatile String current_scene = "";

    /**
     * 上一个所在场景
     */
    public volatile String pre_scene = "";

    public volatile int fightType = 0;

    /**
     * 用户缓存的场景下的实体状态集合
     */
    public volatile static Map<String, GameEntity.AllRole> allRoleMap = new HashMap<>();

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //保存好上下文资源
        gateServerConnCtx = ctx;
        this.roleServiceCache = SpringContextHolder.getBean("roleServiceCache");
        this.userServiceCache = SpringContextHolder.getBean("userServiceCache");
        this.pveFightingService = SpringContextHolder.getBean("pVEFightingService");
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Message msg) throws Exception {
//        logger.info("Client收到Server的消息 : ", msg.getClass().getSimpleName());

        ReceiveMsg receiveMsg = SpringContextHolder.getBean(ParseMap.msg2ptoNum.get(msg.getClass()).toString());
        receiveMsg.execute(msg);
    }

    private void sendGameBossSceneMessage(String bossSceneId, List<String> monsterIdList) {
        //保存进入副本前的场景，方便返回原场景
        pre_scene = current_scene;
        GameBossScene.CGameBossSceneMsg.Builder cgbsmb = GameBossScene.CGameBossSceneMsg.newBuilder();
        cgbsmb.setBossSceneId(bossSceneId);
        cgbsmb.setOldSceneId(current_scene);
        monsterIdList.forEach(monsterId -> {
            cgbsmb.addMonsterS(GameBossScene.stringMsg.newBuilder().setStringId(monsterId).build());
        });
        ByteBuf byteBuf = ClientProtoUtils.pack2Server(current_scene, cgbsmb.build());
        gateServerConnCtx.writeAndFlush(byteBuf);
    }

    /**
     * 获取用户的角色
     *
     * @param selfId
     */
    public void sendGetRoleMessage(String selfId) {
        Game.CGameRoleMsg.Builder crm = Game.CGameRoleMsg.newBuilder();
        crm.setUserId(selfId);
        crm.setScene(current_scene);
        ByteBuf sendBuf = ClientProtoUtils.pack2Server(current_scene, crm.build());
        gateServerConnCtx.writeAndFlush(sendBuf);
    }

    /**
     * 选择地图上的实体进行对应的操作
     */
    public void selectEntityNumWork(GameEntity.AllRole allRole, Scanner sc) {
        if (allRole.getLabel() == AllRoleLabel.NPC) {
            System.out.println("您选择了Npc:" + allRole.getNickname());
            sendNpcMessage(allRole.getAllRoleId());
        } else if (allRole.getLabel() == AllRoleLabel.MONSTER) {
            List<String> monsterIdList = new LinkedList<>();
            monsterIdList.add(allRole.getAllRoleId());
            sendGameBossSceneMessage(UUIDUtil.getUUID(), monsterIdList);
            System.out.println("战斗已经开始，输入  out   可以提前结束战斗,并返回原来的场景!");
            String out = sc.nextLine();
            if (out.equals("out")) {
                pveFightingService.shutDownExecutor();
                //战斗结束了，所以需要返回之前的场景
                sendMoveMessage(pre_scene);
                logger.info("你选择结束战斗退出，返回原来场景！");
            }
        }
    }

    public void selectEntityNumWork(GameEntity.Role role, Scanner sc){

    }

    /**
     * 发送获取用户登入初始化消息
     *
     * @param userId
     */
    public void sendUserLoginInitMsg(String userId) {
        Game.CGameUserLoginInitMsg.Builder cgulimb = Game.CGameUserLoginInitMsg.newBuilder();
        cgulimb.setSenderId(userId);
        ByteBuf byteBuf = ClientProtoUtils.pack2Server(current_scene, cgulimb.build());
        gateServerConnCtx.writeAndFlush(byteBuf);
    }

    /**
     * 装备相关消息
     *
     * @param code
     * @param roleId
     * @param backpackId
     * @param weaponry
     */
    public void sendWeaponryMessage(Integer code, String roleId, String backpackId, GameEntity.Weaponry weaponry) {
        GameBackpack.CGameWeaponryMsg.Builder cgwmb = GameBackpack.CGameWeaponryMsg.newBuilder();
        cgwmb.setCode(code);
        cgwmb.setRoleId(roleId);
        if (backpackId != null) {
            cgwmb.setBackpackId(backpackId);
        }
        if (weaponry != null) {
            cgwmb.setWeaponry(weaponry);
        }
        ByteBuf sendBuf = ClientProtoUtils.pack2Server(current_scene, cgwmb.build());
        gateServerConnCtx.writeAndFlush(sendBuf);
    }

    /**
     * 发送物品相关消息
     *
     * @param code
     * @param roleId
     * @param backpackId
     * @param item
     */
    public void sendItemMessage(Integer code, String roleId, String backpackId, GameEntity.Item item, String attachment) {
        GameBackpack.CGameItemMsg.Builder cgimb = GameBackpack.CGameItemMsg.newBuilder();
        cgimb.setCode(code);
        cgimb.setRoleId(roleId);
        if (backpackId != null) {
            cgimb.setBackpackId(backpackId);
        }
        if (item != null) {
            cgimb.setItem(item);
        }
        if (attachment != null) {
            cgimb.setAttachment(attachment);
        }
        ByteBuf sendBuf = ClientProtoUtils.pack2Server(current_scene, cgimb.build());
        gateServerConnCtx.writeAndFlush(sendBuf);
    }

    /**
     * 发送商城请求
     *
     * @param code
     * @param commodityId
     * @param count
     */
    public void sendShopMessage(Integer code, String commodityId, Integer count) {
        GameShop.CGameShopMsg cGameShopMsg = GameShop.CGameShopMsg.newBuilder()
                .setCode(code)
                .setCommodityId(commodityId)
                .setCount(count)
                .build();
        ByteBuf sendBuf = ClientProtoUtils.pack2Server(current_scene, cGameShopMsg);
        gateServerConnCtx.writeAndFlush(sendBuf);
    }

    /**
     * 发送攻击消息
     *
     * @param allRoleId
     * @param allRoleId2
     * @param skillId
     */
    public void sendAttackMessage(String allRoleId, String allRoleId2, String skillId) {
        Game.CGameAttack.Builder cab = Game.CGameAttack.newBuilder();
        cab.setSenderId(allRoleId);
        cab.setReceiverId(allRoleId2);
        cab.setSkillId(skillId);
        cab.setSceneName(current_scene);
        Game.CGameAttack cGameAttack = cab.build();
        ByteBuf sendBuf = ClientProtoUtils.pack2Server(current_scene, cGameAttack);
        gateServerConnCtx.writeAndFlush(sendBuf);
    }

    /**
     * 发送与npc对话请求
     *
     * @param allRoleId
     */
    private void sendNpcMessage(String allRoleId) {
        Game.CGameChatMsg.Builder cb = Game.CGameChatMsg.newBuilder();
        cb.setSenderId(selfId);
        cb.setReceiverId(allRoleId);
        cb.setContent("请求对话！");
        Game.CGameChatMsg cGameChatMsg = cb.build();
        ByteBuf sendBuf = ClientProtoUtils.pack2Server(current_scene, cGameChatMsg);
        gateServerConnCtx.writeAndFlush(sendBuf);
    }

    /**
     * 登入
     *
     * @param userId
     * @param password
     */
    public void login(String userId, String password) {
        Auth.CLogin.Builder lb = Auth.CLogin.newBuilder();
        lb.setUserId(userId);
        lb.setPassword(password);
        //创建CLogin消息体
        Auth.CLogin cLogin = lb.build();
        //向服务器发送登录消息
        ByteBuf sendBuf = ClientProtoUtils.pack2Server(current_scene, cLogin);
        gateServerConnCtx.writeAndFlush(sendBuf);
        logger.info("Client1 发送登入消息给服务器, userId = {}", userId);
    }

    /**
     * 注册账号
     *
     * @param
     */
    public void registerAccount(String userId, String password, String nickName) {
        Auth.CRegister.Builder crb = Auth.CRegister.newBuilder();
        crb.setUserId(userId);
        crb.setPassword(password);
        crb.setNickName(nickName);
        //创建cRegister消息体
        Auth.CRegister cRegister = crb.build();
        //向服务器发送注册消息
        ByteBuf sendBuf = ClientProtoUtils.pack2Server(current_scene, cRegister);
        gateServerConnCtx.writeAndFlush(sendBuf);
        logger.info("Client1 发送注册消息给服务器, userId = {}", userId);
    }

    /**
     * 发送移动场景请求
     *
     * @param nextScene
     */
    public void sendMoveMessage(String nextScene) {
        //构建移动消息对象
        Game.CGameMove.Builder cb = Game.CGameMove.newBuilder();
        cb.setSenderId(selfId);
        cb.setCurrentScene(current_scene);
        cb.setNextScene(nextScene);
        Game.CGameMove cGameMove = cb.build();
        ByteBuf buf = ClientProtoUtils.pack2Server(current_scene, cGameMove);
        gateServerConnCtx.writeAndFlush(buf);
    }

    /**
     * 发送获取用户技能消息
     *
     * @param allRoleIdList
     */
    public void sendSkillMessage(int code, List<String> allRoleIdList) {
        Game.CGameSkillMsg.Builder cb = Game.CGameSkillMsg.newBuilder();
        cb.setCode(code);
        GameEntity.stringMsg.Builder smb = GameEntity.stringMsg.newBuilder();
        List<GameEntity.stringMsg> stringMsgList = new ArrayList<>();
        allRoleIdList.forEach(allRoleId -> stringMsgList.add(smb.setStringId(allRoleId).build()));
        cb.addAllSenderId(stringMsgList);
        Game.CGameSkillMsg cGameSkillMsg = cb.build();
        ByteBuf byteBuf = ClientProtoUtils.pack2Server(current_scene, cGameSkillMsg);
        gateServerConnCtx.writeAndFlush(byteBuf);
        logger.info("实体  " + allRoleIdList.toString() + "  技能获取请求已发送！！！");
    }

    /**
     * 发送显示场景实体请求
     */
    public void sendAoiMessage() {
        Game.CGameAoi.Builder cb = Game.CGameAoi.newBuilder();
        cb.setSenderId(selfId);
        cb.setScene(current_scene);
        Game.CGameAoi cGameAoi = cb.build();
        ByteBuf buf = ClientProtoUtils.pack2Server(current_scene, cGameAoi);
        gateServerConnCtx.writeAndFlush(buf);
        logger.info("场景角色请求已发送！！！");
    }

    /**
     * 更新少数场景实体情况
     */
    public void updateAOIAllRole(List<GameEntity.AllRole> allRoleList) {
        System.out.println("当前场景的实体情况更新：");
        for (GameEntity.AllRole allRole : allRoleList) {
            allRoleMap.put(allRole.getAllRoleId(), allRole);
            String printToString = JsonFormat.printToString(allRole);
            System.out.println(allRole.getAllRoleId() + ": " + printToString);
        }
    }

    public void updateAOIRole(List<GameEntity.Role> roleList) {
        System.out.println("角色状态更新：");
        roleList.forEach(role -> {
            if (!roleServiceCache.getRoleInMap().containsKey(role.getAllRole().getAllRoleId())) {
                RoleServiceCache.RoleIn roleIn = roleServiceCache.new RoleIn();
                roleServiceCache.getRoleInMap().put(role.getAllRole().getAllRoleId(), roleIn);
            }
            roleServiceCache.getRoleInMap().get(role.getAllRole().getAllRoleId()).setRole(role);
            String printToString = JsonFormat.printToString(role);
            System.out.println(role.getAllRole().getAllRoleId() + ": " + printToString);
        });
    }


    /**
     * 切换场景类场景实体全部更新
     *
     * @param allRoleList
     */
    public void updateAllAOIAllRole(List<GameEntity.AllRole> allRoleList) {
        System.out.println("当前场景的实体情况更新：");
        allRoleMap.clear();
        for (GameEntity.AllRole allRole : allRoleList) {
            allRoleMap.put(allRole.getAllRoleId(), allRole);
            String printToString = JsonFormat.printToString(allRole);
            System.out.println(allRole.getAllRoleId() + ": " + printToString);
        }
        System.out.println();
    }

    public String getCurrent_scene() {
        return current_scene;
    }

    public void setCurrent_scene(String current_scene) {
        this.current_scene = current_scene;
    }

    public void sendOneToOneChat(String userId2, String content) {
        GameChat.OneToOneChat.Builder otocb = GameChat.OneToOneChat.newBuilder();
        otocb.setSenderId(selfId);
        otocb.setReceiverId(userId2);
        otocb.setContent(content);
        ByteBuf byteBuf = ClientProtoUtils.pack2Server(current_scene, otocb.build());
        gateServerConnCtx.writeAndFlush(byteBuf);
    }

    public void sendOneToOneChatOld(String userId2) {
        GameChat.OneToOneChatOld.Builder otocob = GameChat.OneToOneChatOld.newBuilder();
        otocob.setUserId2(userId2);
        ByteBuf byteBuf = ClientProtoUtils.pack2Server(current_scene, otocob.build());
        gateServerConnCtx.writeAndFlush(byteBuf);
    }

    public void sendWorldPlayerChatOld(String selfId) {
        GameChat.WorldPlayerChatOld worldPlayerChatOld = GameChat.WorldPlayerChatOld.newBuilder().setCode(selfId).build();
        ByteBuf byteBuf = ClientProtoUtils.pack2Server(current_scene, worldPlayerChatOld);
        gateServerConnCtx.writeAndFlush(byteBuf);
    }

    public void sendWorldPlayerChat(String content) {
        GameChat.WorldPlayerChat.Builder wpcb = GameChat.WorldPlayerChat.newBuilder();
        wpcb.setSenderId(clientHandler.selfId);
        wpcb.setContent(content);
        ByteBuf byteBuf = ClientProtoUtils.pack2Server(current_scene, wpcb.build());
        gateServerConnCtx.writeAndFlush(byteBuf);
    }

    public void sendCreateRole(int code, String profession, String roleName) {
        GameRole.CGameCreateRoleMsg.Builder cgcrb = GameRole.CGameCreateRoleMsg.newBuilder();
        cgcrb.setCode(code);
        cgcrb.setProfession(profession);
        cgcrb.setRoleName(roleName);
        cgcrb.setUserId(selfId);
        ByteBuf byteBuf = ClientProtoUtils.pack2Server(current_scene, cgcrb.build());
        gateServerConnCtx.writeAndFlush(byteBuf);
    }

    public void sendEmail(int code) {

    }
    public void sendEmail(int code, String emailId) {
        GameEmail.WorldPlayerEmailMsg.Builder wpemb = GameEmail.WorldPlayerEmailMsg.newBuilder();
        wpemb.setCode(code);
        wpemb.addEmailId(GameEmail.StringMsg.newBuilder().setStringId(emailId).build());
        ByteBuf byteBuf = ClientProtoUtils.pack2Server(current_scene, wpemb.build());
        gateServerConnCtx.writeAndFlush(byteBuf);
    }


    public void sendGetAllEmail(int code) {
        GameEmail.WorldPlayerEmailMsg.Builder wpemb = GameEmail.WorldPlayerEmailMsg.newBuilder();
        wpemb.setCode(code);
        ByteBuf byteBuf = ClientProtoUtils.pack2Server(current_scene, wpemb.build());
        gateServerConnCtx.writeAndFlush(byteBuf);
    }

    public void sendPvpSceneMessage(String userId2) {
        GameBossScene.CGamePvpSceneMsg.Builder cgpsb = GameBossScene.CGamePvpSceneMsg.newBuilder();
        cgpsb.setBossSceneId(UUIDUtil.getUUID());
        cgpsb.setFightId(userId2);
        cgpsb.setOldSceneId(current_scene);
        ByteBuf byteBuf = ClientProtoUtils.pack2Server(current_scene, cgpsb.build());
        gateServerConnCtx.writeAndFlush(byteBuf);
    }

    /**
     * 队伍管理请求消息协议
     * @param code
     * @param teamName
     */
    public void sendTeamMsg(int code, String teamName) {
        GameTeam.TeamMsg.Builder tmb = GameTeam.TeamMsg.newBuilder();
        tmb.setCode(code);
        tmb.setTeamName(teamName);
        ByteBuf byteBuf = ClientProtoUtils.pack2Server(current_scene, tmb.build());
        gateServerConnCtx.writeAndFlush(byteBuf);
    }

    public void sendTradingMsg(int code, String stringId, GameTrading.Trading trading) {
        GameTrading.TradingMsg.Builder tmb = GameTrading.TradingMsg.newBuilder();
        tmb.setCode(code);
        if (stringId != null){
            tmb.setStringId(stringId);
        }
        if (trading != null){
            tmb.setTrading(trading);
        }
        ByteBuf byteBuf = ClientProtoUtils.pack2Server(current_scene, tmb.build());
        gateServerConnCtx.writeAndFlush(byteBuf);
    }

    public void sendGuildMsg(int code) {
        GameGuild.GuildMsg.Builder gmb = GameGuild.GuildMsg.newBuilder();
        gmb.setCode(code);
        ByteBuf byteBuf = ClientProtoUtils.pack2Server(current_scene, gmb.build());
        gateServerConnCtx.writeAndFlush(byteBuf);
    }

    public void sendTradingMsg(int code, GameGuild.GuildUser guildUser1) {
        GameGuild.GuildMsg.Builder gmb = GameGuild.GuildMsg.newBuilder();
        gmb.setCode(code);
        if (guildUser1 != null){
            gmb.addGuildUser(guildUser1);
        }
        ByteBuf byteBuf = ClientProtoUtils.pack2Server(current_scene, gmb.build());
        gateServerConnCtx.writeAndFlush(byteBuf);
    }

    public void sendGuildMsg(int code, GameGuild.Guild guild) {
        GameGuild.GuildMsg.Builder gmb = GameGuild.GuildMsg.newBuilder();
        gmb.setCode(code);
        if (guild != null){
            gmb.setGuild(guild);
        }
        ByteBuf byteBuf = ClientProtoUtils.pack2Server(current_scene, gmb.build());
        gateServerConnCtx.writeAndFlush(byteBuf);
    }

    public void sendGuildMsg(int code, String string, GameGuild.Guild guild) {
        GameGuild.GuildMsg.Builder gmb = GameGuild.GuildMsg.newBuilder();
        gmb.setCode(code);
        if (string != null){
            gmb.setString(string);
        }
        if (guild != null){
            gmb.setGuild(guild);
        }
        ByteBuf byteBuf = ClientProtoUtils.pack2Server(current_scene, gmb.build());
        gateServerConnCtx.writeAndFlush(byteBuf);
    }

    public void sendTradingShopMsg(int code) {
        GameTradingShop.TradingShopMsg.Builder tsmb = GameTradingShop.TradingShopMsg.newBuilder();
        tsmb.setCode(code);
        ByteBuf byteBuf = ClientProtoUtils.pack2Server(current_scene, tsmb.build());
        gateServerConnCtx.writeAndFlush(byteBuf);
    }

    public void sendTradingShopMsg(int code, GameTradingShop.TradingShop tradingShop) {
        GameTradingShop.TradingShopMsg.Builder tsmb = GameTradingShop.TradingShopMsg.newBuilder();
        tsmb.setCode(code);
        tsmb.setTradingShop(tradingShop);
        ByteBuf byteBuf = ClientProtoUtils.pack2Server(current_scene, tsmb.build());
        gateServerConnCtx.writeAndFlush(byteBuf);
    }

    public void sendTradingShopMsg(int code, String selfBackpackId, GameTradingShop.TradingShop tradingShop) {
        GameTradingShop.TradingShopMsg.Builder tsmb = GameTradingShop.TradingShopMsg.newBuilder();
        tsmb.setCode(code);
        tsmb.setString(selfBackpackId);
        tsmb.setTradingShop(tradingShop);
        ByteBuf byteBuf = ClientProtoUtils.pack2Server(current_scene, tsmb.build());
        gateServerConnCtx.writeAndFlush(byteBuf);
    }
    public void sendTradingShopMsg(int code, GameTradingShop.TradingShop tradingShop,
                                   GameTradingShop.TradingShopRecord tradingShopRecord) {
        GameTradingShop.TradingShopMsg.Builder tsmb = GameTradingShop.TradingShopMsg.newBuilder();
        tsmb.setCode(code);
        tsmb.setTradingShop(tradingShop);
        tsmb.setTradingShopRecord(tradingShopRecord);
        ByteBuf byteBuf = ClientProtoUtils.pack2Server(current_scene, tsmb.build());
        gateServerConnCtx.writeAndFlush(byteBuf);
    }
}









